#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <ctemplate/template.h> // CTemplate在服务器启动时加载了模板到内存中。
#include "oj_model2.hpp"
/*
第一次直接使用了ctemplate的文件模版，但有一个缺点。就是当访问服务器all_questions或者one_quesion时，
ctemplate由于缓存了第一次的html。导致刷新没反应。需要重新重启服务器
于是改为了字符串版。每次读取都是需要重新读取，确保每次请求都重新加载模板文件
这样，每次修改HTML文件后，刷新页面就能看到最新的内容，而不需要重启服务器。
*/
namespace ns_view
{
    using namespace ns_model;
    const static std::string template_path = "./template/";
    class View
    {
    public:
        View() {}

    public:
        void ViewAllQuestions(const std::vector<Question> &questions, std::string *out)
        {
            if (out == nullptr)
                return;
            // 形成网页
            // 每次都从文件加载模板，而不是使用缓存
            std::string inhtml = template_path + "all_questions.html";
            std::ifstream in(inhtml);
            if (!in.is_open())
            {
                LOG(LogLevel::ERROR) << "无法打开模板文件: " << inhtml;
                return;
            }
            // 读取文件内容。比getline好
            std::string template_content({std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>()}); // 避免看成函数声明
            in.close();
            // 形成数据字典
            ctemplate::TemplateDictionary root("all_questions");
            for (const auto &q : questions)
            {
                ctemplate::TemplateDictionary *sub = root.AddSectionDictionary("questions_list");
                sub->SetValue("number", q.number);
                sub->SetValue("title", q.title);
                sub->SetValue("star", q.star);
            }

            // 使用字符串模板而不是文件模板
            // 获取被渲染网页对对象----一开始CTemplate在服务器启动时加载了模板到内存中。
            // ctemplate::Template *tpl = ctemplate::Template::GetTemplate(inhtml, ctemplate::DO_NOT_STRIP);
            ctemplate::TemplateString tpl_string(template_content);
            ctemplate::Template *tpl = ctemplate::Template::StringToTemplate(tpl_string, ctemplate::DO_NOT_STRIP);

            if (tpl == nullptr)
            {
                LOG(LogLevel::ERROR) << "模板解析失败: " << inhtml;
                return;
            }
            // 渲染
            tpl->Expand(out, &root);
        }

        void ViewOneQuestion(const Question &q, std::string *out)
        {
            if (out == nullptr)
                return;
            // 形成网页
            std::string inhtml = template_path + "one_question.html";
            std::ifstream in(inhtml);
            if (!in.is_open())
            {
                LOG(LogLevel::ERROR) << "无法打开模板文件: " << inhtml;
                return;
            }
            // 读取文件内容。比getline好
            std::string template_content({std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>()});
            in.close();
            // 形成数据字典
            ctemplate::TemplateDictionary root("one_question");
            root.SetValue("dest", q.dest);
            root.SetValue("header", q.header);
            root.SetValue("number", q.number);
            root.SetValue("title", q.title);
            root.SetValue("star", q.star);
            root.SetValue("cpu_limit", std::to_string(q.cpu_limit));
            root.SetValue("mem_limit", std::to_string(q.mem_limit));
            // 获取渲染网页对象
            ctemplate::TemplateString tpl_string(template_content);
            ctemplate::Template *tpl = ctemplate::Template::StringToTemplate(tpl_string, ctemplate::DO_NOT_STRIP);
            if (tpl == nullptr)
            {
                LOG(LogLevel::ERROR) << "模板解析失败: " << inhtml;
                return;
            }
            // 渲染
            tpl->Expand(out, &root);
        }

        // 文件版本
        // void ViewOneQuestion(const Question &q, std::string *out)
        // {
        //     if (out == nullptr)
        //         return;
        //     // 形成网页
        //     std::string inhtml = template_path + "one_question.html";
        //     // 形成数据字典
        //     ctemplate::TemplateDictionary root("one_question");
        //     root.SetValue("dest", q.dest);
        //     root.SetValue("header", q.header);
        //     root.SetValue("number", q.number);
        //     root.SetValue("title", q.title);
        //     root.SetValue("star", q.star);
        //     root.SetValue("cpu_limit", std::to_string(q.cpu_limit));
        //     root.SetValue("mem_limit", std::to_string(q.mem_limit));
        //     // 获取渲染网页对象
        //     ctemplate::Template *tpl = ctemplate::Template::GetTemplate(inhtml, ctemplate::DO_NOT_STRIP);
        //     // 渲染
        //     tpl->Expand(out, &root);
        // }
    };
}